package com.bmob.lover.data.repository

import android.net.Uri
import android.text.TextUtils
import com.luck.picture.lib.config.PictureMimeType
import com.bmob.lover.app.ext.getCreatePostJson
import com.bmob.lover.app.ext.getExposeJson
import com.bmob.lover.app.ext.toJson
import com.bmob.lover.data.model.net.PageInfo
import com.bmob.lover.app.util.CacheUtil
import com.bmob.lover.data.constant.UrlConstant
import com.bmob.lover.data.model.bean.*
import com.theone.mvvm.base.appContext
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import rxhttp.toParser
import rxhttp.wrapper.cahce.CacheMode
import rxhttp.wrapper.entity.ParameterizedTypeImpl
import rxhttp.wrapper.entity.Progress
import rxhttp.wrapper.param.Method
import rxhttp.wrapper.param.RxHttp
import rxhttp.wrapper.param.toFlowResponse
import rxhttp.wrapper.param.toResponse
import the.one.brand.net.ResponseParse
import java.io.File
import java.lang.reflect.Type

//  ┏┓　　　┏┓
//┏┛┻━━━┛┻┓
//┃　　　　　　　┃
//┃　　　━　　　┃
//┃　┳┛　┗┳　┃
//┃　　　　　　　┃
//┃　　　┻　　　┃
//┃　　　　　　　┃
//┗━┓　　　┏━┛
//    ┃　　　┃                  神兽保佑
//    ┃　　　┃                  永无BUG！
//    ┃　　　┗━━━┓
//    ┃　　　　　　　┣┓
//    ┃　　　　　　　┏┛
//    ┗┓┓┏━┳┓┏┛
//      ┃┫┫　┃┫┫
//      ┗┻┛　┗┻┛
/**
 * @author The one
 * @date 2021-09-13 16:04
 * @describe TODO
 * @email 625805189@qq.com
 * @remark
 */
class BmobRepository private constructor() {

    private object Holder {
        val INSTANCE = BmobRepository()
    }

    companion object {
        val INSTANCE = Holder.INSTANCE
        const val TIME_OUT = 60 * 1000L
    }

    suspend fun <T> requestList(
        type: Type,
        url: String,
        page: Int,
        cacheMode: CacheMode,
        bql: String,
        where: String,
        order: String,
        include: String,
        keys: String,
        sum: String,
        groupBy: String,
        groupCount: Boolean,
        limit: Int,
        skip: Boolean
    ): BmobList<T> {
        val response = with(
            RxHttp.get(url)
                .setCacheMode(cacheMode)
                .setCacheValidTime(-1)
        ) {
            if (!TextUtils.isEmpty(bql)) {
                add("bql", bql)
            } else {
                add("where", where, !TextUtils.isEmpty(where))
                    .add("order", order, !TextUtils.isEmpty(order))
                    .add("include", include, !TextUtils.isEmpty(include))
                    .add("keys", keys, !TextUtils.isEmpty(keys))
                    .add("sum", sum, !TextUtils.isEmpty(sum))
                    .add("groupby", groupBy, !TextUtils.isEmpty(groupBy))
                    .add("groupcount", groupCount, groupCount)
                    .add("limit", limit, skip)
                    .add("skip", (page - 1) * limit, skip)
            }
        }.toParser(object :
            ResponseParse<BmobList<T>>(
                ParameterizedTypeImpl[BmobList::class.java, type]
            ) {}
        )
            .await()
        val total = if (skip && (response.results?.size == limit)) page + 1 else page
        response.pageInfo = PageInfo(page, total, limit)
        return response
    }

    suspend fun doAction(
        url: String,
        method: Method, tableName: String, objectId: String, json: String
    ): Flow<BmobResultBean> {
        val requestUrl = "$url/$objectId"
        val param = when (method) {
            Method.POST -> RxHttp.postJson(url)
            Method.PUT -> {
                RxHttp.putJson(requestUrl)
            }
            else -> RxHttp.deleteJson(requestUrl)
        }
        if (tableName == "_User") {
            param.addHeader("X-Bmob-Session-Token", CacheUtil.getSessionToken())
        }
        val p = if (json.isNotEmpty()) {
            param.addAll(json.replace(",\"objectId\":\"$objectId\"", ""))
        } else {
            param
        }
        return p.toFlowResponse<BmobResultBean>()
//            .await()
//        response.msg = when (method) {
//            Method.POST -> "添加成功"
//            Method.PUT -> "更新成功"
//            else -> "删除成功"
//        }
//        return response
    }

    suspend fun <T : BmobBean> doBatch(url: String, method: Method, list: List<T>): String {
        val batchBeans = mutableListOf<BmobBatch<T>>()
        list.forEach {
            val requestUrl = when (method) {
                Method.POST -> url
                else -> "$url/${it.objectId}"
            }
            batchBeans.add(BmobBatch(method.name, requestUrl, it.apply {
                objectId = ""
            }))
        }
        var json = when (method) {
            Method.POST -> BmobBatchRequest<T>(batchBeans).toJson().getCreatePostJson()
            else -> {
                BmobBatchRequest<T>(batchBeans).getExposeJson()
            }
        }
        val target = ",\"objectId\":\"\""
        if (json.contains(target)) {
            json = json.replace(target, "")
        }
        RxHttp.postJson(UrlConstant.BATCH)
            .addAll(json)
            .toResponse<String>()
            .await()
        return when (method) {
            Method.POST -> "添加成功"
            Method.PUT -> "更新成功"
            Method.DELETE -> "删除成功"
            else -> "操作成功"
        }
    }

    @ExperimentalCoroutinesApi
    fun uploadFile(fileName: String, filePath: String, progress: suspend (Progress) -> Unit): Flow<BmobFile> {
        return RxHttp.postBody(
            UrlConstant.UPLOAD_FILE + fileName
        ).run {
            filePath.let {
                if (PictureMimeType.isContent(it)) {
                    setBody(Uri.parse(it), appContext)
                } else {
                    setBody(File(it))
                }
            }
            connectTimeout(TIME_OUT)
            readTimeout(TIME_OUT)
            writeTimeout(TIME_OUT)
        }.toFlowResponse<BmobFile>(1,progress)
    }

}